/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.handlers;

import java.util.List;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.util.EList;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.Lifeline;

import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagram.sequence.sedi.edit.FrameEditPart;
import com.cea.papyrus.diagram.sequence.sedi.edit.analysis.CoverableAnalyser;
import com.cea.papyrus.diagram.sequence.sedi.model.command.LifelinePosition;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Handles creation of ExecutionOccurrences.
 * <p>
 * This handler is used from FrameLayoutPolicy.
 * </p>
 * 
 * @author frankd@ifi.uio.no
 */
public class InteractionFragmentCreateHandler implements CreationHandler {
	public final EditPolicy hostPolicy;
	
	protected final FrameEditPart interactionEP;
	protected final GraphNode interactionNode;
	protected final Interaction interaction;
	protected final Diagram diagram;
	
	protected Point absolutLoc;
	protected Point relativeLoc;
	protected Rectangle bounds;
	
	/**
	 * Best covered lifeline and its position
	 */
	protected List<LifelinePosition> bestCovereds;
	protected Lifeline bestCoveredLifeline;
	
	/**
	 * All the lifelines graphically covered by the creation area in the diagram
	 */
	protected List<Lifeline> coveredLifelines;

	/**
	 * Main contructor
	 * @param hostPolicy
	 */
	public InteractionFragmentCreateHandler(final EditPolicy hostPolicy) {
		this.hostPolicy = hostPolicy;
		
		// The ExecutionSpecification is created on the Interaction
		// Retrieve the Interaction EditPart (FrameEditPart) and its GraphNode
		interactionEP = (FrameEditPart) hostPolicy.getHost();
		interactionNode = interactionEP.getGraphNode();
		interaction = ModelUtil.<Interaction> getSemantic(interactionNode);
		// Get the Diagram where the Interaction is shown
		diagram = LookForElement.getDiagram(interactionNode);
	}

	/**
	 * This method must be effectively implemented by inherited classes
	 * It should not be called.
	 * @param request
	 * @return always null
	 */
	public Command[] getCreateCommands(final CreateRequest request) {
		Debug.log(new Exception("The method InteractionFragmentCreateHandler.getCreateCommands() should not be called."));
		return null;
	}
	
	/**
	 * This method initialize class attribute the are dependent from the request
	 * (location, coveredLifeline...),
	 * it is supposed to be called in subclasses getCreateCommands
	 * @param request
	 * @return true if the initialization worked
	 */
	protected boolean initialize(final CreateRequest request) {

		// At least one Lifeline must exist in the Diagram, the Start/Stop 
		// OccurenceSpecification of the new ExecutionSpecification will cover a Lifeline
		// The covered Lifeline directly depend on the position where the user creates the
		// InteractionFragment.
		
		// First, verify that there is at least one Lifeline in the interaction...
		// ... if no Lifeline exist, abort the command creation.
		EList<Lifeline> lifelines = ModelUtil.<Interaction> getSemantic(interactionNode).getLifelines();
		if (lifelines.isEmpty()) {
			return false;
		}
		
		// Keep a copy of the location where the user tries to create the
		// InteractionFragment
		absolutLoc = request.getLocation().getCopy();
		Dimension size = request.getSize();

		// Convert the location to relative location in the interaction
		relativeLoc = absolutLoc.getCopy();
		interactionEP.getFigure().translateToRelative(relativeLoc);
		interactionEP.getFigure().translateFromParent(relativeLoc);
		
		if (size != null) {
			bounds = new Rectangle(absolutLoc.x, absolutLoc.y, size.width, size.height);
		} else {
			bounds = new Rectangle(absolutLoc.x, absolutLoc.y, 1, 1);
		}

		// Try to find the best covered lifeline
		boolean found = updateBestCovered(bounds);
		// Try to find the covered lifelines
		updateCovered(bounds);
		
		return found;
	}
	
	/**
	 * Find the best covered Lifeline based on the creation location
	 * The new InteractionFragment GraphNode is not required (the command will use the 
	 * creation location to find coverage)... Anyway the InteractionFragment EditPart
	 * is probably not yet created at this step...
	 * 
	 * This method updates the following attibutes :
	 * - bestCovered
	 * - bestCoveredLifeline
	 * 
	 * @param bounds area where lifeline are searched in the diagram
	 * @return true if the best lifeline was found
	 */
	private boolean updateBestCovered(Rectangle bounds) {
		// Find the best covered Lifeline
		// The command needs the Interaction EditPart and the creation location
		// The ExecutionSpecification GraphNode is not required (the command will use the 
		// creation location to find coverage)... Anyway the ExecutionSpecification EditPart
		// is not yet created at this step...		
		final CoverableAnalyser analyser = 
			new CoverableAnalyser(interactionEP, interactionNode);
		
		bestCovereds = analyser.findBestCovered(null, bounds);
		// Log error if the Lifeline on which the ExecutionSpecification is supposed 
		// to be graphically created is not found.
		if (bestCovereds.isEmpty()) {
			Debug.log(new Exception("Unable to find covered Lifeline."));
			return false;
		}
		LifelinePosition coveredLifelinePosition = bestCovereds.get(0);
		bestCoveredLifeline = coveredLifelinePosition.getLifeline();
		return true;
	}
	
	/**
	 * Find the covered Lifelines based on the creation location
	 * The new InteractionFragment GraphNode is not required (the command will use the 
	 * creation location to find coverage)... Anyway the InteractionFragment EditPart
	 * is probably not yet created at this step...
	 * 
	 * This method updates the following attibutes :
	 * - covereds
	 * - coveredLifelines
	 * 
	 * @param bounds area where lifeline are searched in the diagram
	 * @return true if the best lifeline was found
	 */
	private void updateCovered(Rectangle bounds) {
		// Find the best covered Lifeline
		// The command needs the Interaction EditPart and the creation location
		// The ExecutionSpecification GraphNode is not required (the command will use the 
		// creation location to find coverage)... Anyway the ExecutionSpecification EditPart
		// is not yet created at this step...		
		final CoverableAnalyser analyser = 
			new CoverableAnalyser(interactionEP, interactionNode);
		
		coveredLifelines = analyser.findCoveredLifelines(null, bounds);
		if (coveredLifelines.isEmpty()) {
			coveredLifelines.add(bestCoveredLifeline);
		}
	}
}
